package com.xxd.dfs.client;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.UUID;

/**
 * @author: XiaoDong.Xie
 * @create: 2020-09-07 10:58
 * @description: NIO 工具
 */
public class NIOClient {

    private NetworkManager networkManager;

    public NIOClient() {
        this.networkManager = new NetworkManager();
    }

    /**
     * 发送一个文件给datanode
     * 1、尝试建立连接（长连接）
     * 2、创建一个发送请求
     * 3、直接发送
     * 主要是应用协议 数据格式 设计
     * <p>
     * *************************************************
     * 请求类型 + 请求文件名称长度  + 文件名 + 文件长度   + 文件
     * 4     +      4           + N 位   + 8 位     +  N 位
     * *************************************************
     *
     * @param fileInfo 文件信息
     * @param host     host 主机
     * @return
     */
    public boolean sendFile(FileInfo fileInfo, Host host, ResponseCallback callback) {
        if (!networkManager.connectToDN(host)) {
            return false;
        }

        /**
         * hadoop 在这里发送数据
         * 1、会把数据组装成一个个的packet，塞满一个block的时候，就会以一个空包packet 结尾
         * 2、这些packet 会被放入一个dataQueue 里面去
         * 3、初始化一个接收响应的ResponseProcess 线程 里面有一个ackQueue
         * 4、发送数据的时候，以一个packet 为单位发送出去， 这个packet 会从dataQueue 出来进入ackQueue里面去
         * 5、如果datanode 成功响应了，ResponseProcess 就会知道是哪个packet成功了，就会从ackQueue队列里面给移除掉
         * 6、如果失败了，机会把ackQueue里面的packet 挪到 dataQueue里面去重试发送
         */
        NetworkRequest request = createSendFileRequest(fileInfo, host, callback);
        networkManager.sendRequest(request);

        return true;
    }

    /**
     * 创建一个发送文件的请求
     *
     * @param fileInfo
     * @param host
     * @return
     */
    private NetworkRequest createSendFileRequest(FileInfo fileInfo, Host host, ResponseCallback callback) {
        NetworkRequest request = new NetworkRequest();
        ByteBuffer buffer = ByteBuffer.allocate(NetworkRequest.REQUEST_TYPE +
                NetworkRequest.FILENAME_LENGTH + fileInfo.getFileName().getBytes().length +
                NetworkRequest.FILE_LENGTH + fileInfo.getFileLength()
        );

        buffer.putInt(NetworkRequest.REQUEST_SEND_FILE);

        buffer.putInt(fileInfo.getFileName().getBytes().length);
        buffer.put(fileInfo.getFileName().getBytes());

        buffer.putLong(fileInfo.getFileLength());
        buffer.put(fileInfo.getFile());
        buffer.rewind();

        request.setId(UUID.randomUUID().toString());
        request.setHostname(host.getHostname());
        request.setRequestType(NetworkRequest.REQUEST_SEND_FILE);
        request.setIp(host.getIp());
        request.setNioPort(host.getNioPort());
        request.setBuffer(buffer);
        request.setNeedResponse(false);
        request.setCallback(callback);
        return request;

    }


}
